package org.jeecg.common.util;

import io.minio.*;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import okhttp3.OkHttpClient;
import org.jeecg.common.constant.SymbolConstant;
import org.jeecg.common.util.filter.SsrfFileTypeFilter;
import org.jeecg.common.util.filter.StrAttackFilter;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URLDecoder;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Date;

/**
 * minio文件上传工具类
 * @author: jeecg-boot
 */
@Slf4j
public class MinioUtil {
    private static String minioUrl;
    private static String minioName;
    private static String minioPass;
    private static String bucketName;

    public static void setMinioUrl(String minioUrl) {
        MinioUtil.minioUrl = minioUrl;
    }

    public static void setMinioName(String minioName) {
        MinioUtil.minioName = minioName;
    }

    public static void setMinioPass(String minioPass) {
        MinioUtil.minioPass = minioPass;
    }

    public static void setBucketName(String bucketName) {
        MinioUtil.bucketName = bucketName;
    }

    public static String getMinioUrl() {
        return minioUrl;
    }

    public static String getBucketName() {
        return bucketName;
    }

    private static MinioClient minioClient;


//    /**
//     * 上传文件（支持图片压缩）
//     *
//     * @param file      MultipartFile 文件
//     * @param bizPath   业务路径（可传入或由方法内确定）
//     * @param customBucket 自定义存储桶名称
//     * @return 文件访问URL
//     */
//    public static String upload(MultipartFile file, String bizPath, String customBucket) throws Exception {
//        initMinio(minioUrl, minioName, minioPass);
////        MinioClient minioClient = new MinioClient(minioUrl, minioName, minioPass);
//        String fileUrl = "";
//        String orgName = file.getOriginalFilename();
//
//        if (orgName == null || orgName.isEmpty()) {
//            orgName = file.getName();
//        }
//
//        orgName = CommonUtils.getFileName(orgName);
//        String contentType = guessContentTypeFromName(orgName);
//
//        // 判断是否是图片类型，不是则直接上传不压缩
//        boolean isImage = contentType != null && contentType.startsWith("image/");
//        if (!isImage) {
//            log.info("非图片文件，跳过压缩处理");
//            return uploadWithoutCompression(file, bizPath, customBucket);
//        }
//
//        bizPath = determineFileType(orgName);
//        bizPath = StrAttackFilter.filter(bizPath); // 防止攻击过滤
//        SsrfFileTypeFilter.checkUploadFileType(file); // 文件类型安全检查
//
//        String newBucket = bucketName;
//        if (oConvertUtils.isNotEmpty(customBucket)) {
//            newBucket = customBucket;
//        }
//        InputStream inputStream = file.getInputStream();
//        ByteArrayOutputStream os = new ByteArrayOutputStream();
//        ByteArrayInputStream compressedInputStream = null;
//        try {
//            // 读取原始输入流
////            InputStream inputStream = file.getInputStream();
//
//            // 获取原始大小（MB）
//            double fileSizeInMB = (double) file.getSize() / (1024 * 1024);
//            log.info("Original file size: {} MB", fileSizeInMB);
//
//            // 根据大小设定压缩质量
//            float quality = 1.0f;
//            if (fileSizeInMB < 1.0) {
//                quality = 0.85f; // 几乎无损
//            } else if (fileSizeInMB < 2.0) {
//                quality = 0.65f; // 中等压缩
//            } else {
//                quality = 0.45f;  // 强压缩
//            }
//
//            // 使用Thumbnailator进行压缩（只改画质，不改尺寸）
//
//            Thumbnails.of(inputStream)
//                    .scale(1f) // 保持原图比例和尺寸
//                    .outputQuality(quality)
//                    .toOutputStream(os);
//
//            byte[] compressedBytes = os.toByteArray();
//             compressedInputStream = new ByteArrayInputStream(compressedBytes);
//
//            // 构造对象名
//            String fileName = System.currentTimeMillis() + "-" + orgName;
//            String objectName = bizPath + "/" + DateTimeUtils.getFormatDate(new Date(), DateTimeUtils.PARTDATEFORMAT) + "/" + fileName;
//
//            if (objectName.startsWith(SymbolConstant.SINGLE_SLASH)) {
//                objectName = objectName.substring(1);
//            }
//
//            // 上传到 MinIO
//            PutObjectArgs objectArgs = PutObjectArgs.builder()
//                    .object(objectName)
//                    .bucket(newBucket)
//                    .contentType(contentType)
//                    .stream(compressedInputStream, compressedBytes.length, -1)
//                    .build();
//            System.out.println("minioUrl = " + minioUrl);
//
//            minioClient.putObject(objectArgs);
//            compressedInputStream.close();
//            os.close();
//            inputStream.close();
//
//            fileUrl = minioUrl + newBucket + "/" + objectName;
//
//        } catch (Exception e) {
//            log.error(e.getMessage(), e);
//        }finally {
//            compressedInputStream.close();
//            os.close();
//            inputStream.close();
//        }
//
//        return fileUrl;
//    }

    /**
     * 上传文件（支持智能图片压缩）
     *
     * @param file         MultipartFile 文件
     * @param bizPath      业务路径（可传入或由方法内确定）
     * @param customBucket 自定义存储桶名称
     * @param maxWidth     最大宽度限制，0表示不限制
     * @param maxHeight    最大高度限制，0表示不限制
     * @param qualityLevel 质量等级(1-100)，值越高质量越好
     * @return 文件访问URL
     */
    public static String upload(MultipartFile file, String bizPath, String customBucket,
                                int maxWidth, int maxHeight, int qualityLevel) throws Exception {
        initMinio(minioUrl, minioName, minioPass);
        String fileUrl = "";
        String orgName = file.getOriginalFilename();

        if (orgName == null || orgName.isEmpty()) {
            orgName = file.getName();
        }

        orgName = CommonUtils.getFileName(orgName);
        String contentType = guessContentTypeFromName(orgName);

        // 判断是否是图片类型，不是则直接上传不压缩
        boolean isImage = contentType != null && contentType.startsWith("image/");
        if (!isImage) {
            log.info("非图片文件，跳过压缩处理");
            return uploadWithoutCompression(file, bizPath, customBucket);
        }
        // 验证并调整质量等级
        qualityLevel = Math.max(1, Math.min(100, qualityLevel));
        float quality = qualityLevel / 100.0f;

        bizPath = determineFileType(orgName);
        bizPath = StrAttackFilter.filter(bizPath); // 防止攻击过滤
        SsrfFileTypeFilter.checkUploadFileType(file); // 文件类型安全检查

        String newBucket = bucketName;
        if (oConvertUtils.isNotEmpty(customBucket)) {
            newBucket = customBucket;
        }

        // 用于资源自动关闭的try-with-resources语句
        try (InputStream inputStream = file.getInputStream();
             ByteArrayOutputStream os = new ByteArrayOutputStream()) {

            // 获取原始大小（MB）
            double fileSizeInMB = (double) file.getSize() / (1024 * 1024);
            log.info("原始文件大小: {} MB, 文件名: {}", fileSizeInMB, orgName);

            // 如果未指定质量，则根据文件大小自动确定
            if (qualityLevel <= 0) {
                if (fileSizeInMB < 0.5) {
                    quality = 0.9f; // 高质量，轻微压缩
                } else if (fileSizeInMB < 2.0) {
                    quality = 0.35f; // 中等质量
                } else {
                    quality = 0.45f; // 高压缩比
                }
            }

            // 读取图片获取原始尺寸
            BufferedImage originalImage = ImageIO.read(inputStream);
            int originalWidth = originalImage.getWidth();
            int originalHeight = originalImage.getHeight();
            log.info("原始图片尺寸: {}x{}", originalWidth, originalHeight);

            // 计算压缩后的尺寸
            int targetWidth = originalWidth;
            int targetHeight = originalHeight;

            // 最大宽度1920，最大高度1080，按比例缩放
            if (maxWidth > 0 || maxHeight > 0) {
                double widthRatio = maxWidth > 0 ? (double) maxWidth / originalWidth : Double.MAX_VALUE;
                double heightRatio = maxHeight > 0 ? (double) maxHeight / originalHeight : Double.MAX_VALUE;
                double scaleRatio = Math.min(widthRatio, heightRatio);

                // 只有当需要缩小时才进行缩放
                if (scaleRatio < 1.0) {
                    targetWidth = (int) (originalWidth * scaleRatio);
                    targetHeight = (int) (originalHeight * scaleRatio);
                    log.info("图片将被缩放到: {}x{}", targetWidth, targetHeight);
                }
            }
            // 特殊处理不同类型的图片
            boolean isPhoto = contentType.contains("jpeg") || contentType.contains("jpg");
            boolean isGraphic = contentType.contains("png") || contentType.contains("gif");

            // 对照片和图形采取不同的压缩策略
            if (isGraphic) {
                // 图形类图片适当提高质量，保证清晰度
                quality = Math.min(0.9f, quality + 0.1f);
            } else if (isPhoto) {
                // 照片类图片可以适当降低质量
                quality = Math.max(0.3f, quality - 0.1f);
            }

            // 使用Thumbnailator进行压缩
            Thumbnails.of(originalImage)
                    .size(targetWidth, targetHeight)
                    .outputQuality(quality)
                    .outputFormat(getFileExtension(orgName))
                    .toOutputStream(os);

            // 计算压缩后的大小
            byte[] compressedBytes = os.toByteArray();
            double compressedSizeInMB = (double) compressedBytes.length / (1024 * 1024);
            log.info("压缩后文件大小: {} MB, 压缩比: {}%",
                    compressedSizeInMB,
                    (int)(compressedSizeInMB / fileSizeInMB * 100));

            // 如果压缩后反而变大，使用原始文件
            if (compressedBytes.length >= file.getSize()) {
                log.warn("压缩后文件变大，将使用原始文件上传");
                return uploadWithoutCompression(file, bizPath, customBucket);
            }

            try (ByteArrayInputStream compressedInputStream = new ByteArrayInputStream(compressedBytes)) {
                // 构造对象名
                String fileName = System.currentTimeMillis() + "-" + orgName;
                String objectName = bizPath + "/" + DateTimeUtils.getFormatDate(new Date(), DateTimeUtils.PARTDATEFORMAT) + "/" + fileName;

                if (objectName.startsWith(SymbolConstant.SINGLE_SLASH)) {
                    objectName = objectName.substring(1);
                }

                // 上传到 MinIO
                PutObjectArgs objectArgs = PutObjectArgs.builder()
                        .object(objectName)
                        .bucket(newBucket)
                        .contentType(contentType)
                        .stream(compressedInputStream, compressedBytes.length, -1)
                        .build();

                minioClient.putObject(objectArgs);
//                fileUrl = minioUrl + newBucket + "/" + objectName;
                fileUrl = newBucket + "/" + objectName;
                log.info("图片上传成功: {}", fileUrl);
            }

        } catch (Exception e) {
            log.error("图片压缩上传失败: {}", e.getMessage(), e);
            throw e; // 重新抛出异常，让调用者处理
        }

        return fileUrl;
    }

    /**
     * 获取文件扩展名
     */
    private static String getFileExtension(String fileName) {
        if (fileName == null || !fileName.contains(".")) {
            return "jpg";
        }
        return fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
    }

    /**
     * 重载方法，使用默认压缩参数
     */
    public static String upload(MultipartFile file, String bizPath, String customBucket) throws Exception {
        // 默认参数：最大宽度1920，最大高度1080，质量等级0（自动判断）
        return upload(file, bizPath, customBucket, 1920, 1080, 0);
    }


    private static String uploadWithoutCompression(MultipartFile file, String bizPath, String customBucket) throws Exception {
        String orgName = file.getOriginalFilename();
        if (orgName == null || orgName.isEmpty()) {
            orgName = file.getName();
        }
        String newBucket = bucketName;
        if (oConvertUtils.isNotEmpty(customBucket)) {
            newBucket = customBucket;
        }

        String contentType = guessContentTypeFromName(orgName);
        String fileName = System.currentTimeMillis() + "-" + orgName;
        String objectName = bizPath + "/" + DateTimeUtils.getFormatDate(new Date(), DateTimeUtils.PARTDATEFORMAT) + "/" + fileName;

        if (objectName.startsWith("/")) {
            objectName = objectName.substring(1);
        }

        PutObjectArgs objectArgs = PutObjectArgs.builder()
                .object(objectName)
                .bucket(newBucket)
                .contentType(contentType)
                .stream(file.getInputStream(), file.getSize(), -1)
                .build();

        minioClient.putObject(objectArgs);
        return minioUrl + newBucket + "/" + objectName;
    }
    /**
     * 上传文件
     * @param file
     * @return
     */
    public static String upload4(MultipartFile file, String bizPath, String customBucket) throws Exception {
//        String fileUrl = "";
//        //update-begin-author:wangshuai date:20201012 for: 过滤上传文件夹名特殊字符，防止攻击
//        bizPath = StrAttackFilter.filter(bizPath);
//        //update-end-author:wangshuai date:20201012 for: 过滤上传文件夹名特殊字符，防止攻击
//
//        //update-begin-author:liusq date:20210809 for: 过滤上传文件类型
//        SsrfFileTypeFilter.checkUploadFileType(file);
//        //update-end-author:liusq date:20210809 for: 过滤上传文件类型
//
//        String newBucket = bucketName;
//        if(oConvertUtils.isNotEmpty(customBucket)){
//            newBucket = customBucket;
//        }
//        try {
//            initMinio(minioUrl, minioName,minioPass);
//            // 检查存储桶是否已经存在
//            if(minioClient.bucketExists(BucketExistsArgs.builder().bucket(newBucket).build())) {
//                log.info("Bucket already exists.");
//            } else {
//                // 创建一个名为ota的存储桶
//                minioClient.makeBucket(MakeBucketArgs.builder().bucket(newBucket).build());
//                log.info("create a new bucket.");
//            }
//            InputStream stream = file.getInputStream();
//            // 获取文件名
//            String orgName = file.getOriginalFilename();
//            if("".equals(orgName)){
//                orgName=file.getName();
//            }
//            orgName = CommonUtils.getFileName(orgName);
////            String bizPath= determineFileType(orgName);
//            String contentType = guessContentTypeFromName(orgName);
////            orgName = CommonUtils.getFileName(orgName);
//            String objectName = bizPath+"/"
//                                +( orgName.indexOf(".")==-1
//                                   ?orgName + "_" + System.currentTimeMillis()
//                                   :orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.lastIndexOf("."))
//                                 );
//
//            // 使用putObject上传一个本地文件到存储桶中。
//            if(objectName.startsWith(SymbolConstant.SINGLE_SLASH)){
//                objectName = objectName.substring(1);
//            }
//            PutObjectArgs objectArgs = PutObjectArgs.builder().object(objectName)
//                    .bucket(newBucket)
//                    .contentType(contentType)
//                    .stream(stream,stream.available(),-1).build();
//            minioClient.putObject(objectArgs);
//            stream.close();
//            fileUrl = minioUrl+newBucket+"/"+objectName;
//        }catch (Exception e){
//            log.error(e.getMessage(), e);
//        }
//        return fileUrl;
//    }
        initMinio(minioUrl, minioName,minioPass);
        String fileUrl = "";
        // 获取文件名
        String orgName = file.getOriginalFilename();
        if ("".equals(orgName)) {
            orgName = file.getName();
        }
        orgName = CommonUtils.getFileName(orgName);
        bizPath= determineFileType(orgName);
        String contentType = guessContentTypeFromName(orgName);
        //update-begin-author:wangshuai date:20201012 for: 过滤上传文件夹名特殊字符，防止攻击
        bizPath = StrAttackFilter.filter(bizPath);   //bizPath   可以理解到底是file 还是image    等等
        //update-end-author:wangshuai date:20201012 for: 过滤上传文件夹名特殊字符，防止攻击

        //update-begin-author:liusq date:20210809 for: 过滤上传文件类型
        SsrfFileTypeFilter.checkUploadFileType(file);
        //update-end-author:liusq date:20210809 for: 过滤上传文件类型

        String newBucket = bucketName;
        if(oConvertUtils.isNotEmpty(customBucket)){
            newBucket = customBucket;
        }
        try {
            // 检查存储桶是否已经存在
//            if(minioClient.bucketExists(BucketExistsArgs.builder().bucket(newBucket).build())) {
//                log.info("Bucket already exists.");
//            } else {
//                // 创建一个名为ota的存储桶
//                minioClient.makeBucket(MakeBucketArgs.builder().bucket(newBucket).build());
//                log.info("create a new bucket.");
//            }
            InputStream stream = file.getInputStream();

            String fileName = System.currentTimeMillis() + "-" + orgName;
            String objectName = bizPath + "/" + DateTimeUtils.getFormatDate(new Date(), DateTimeUtils.PARTDATEFORMAT) + "/" + fileName;
            System.out.println("objectName = " + objectName);

            // 使用putObject上传一个本地文件到存储桶中。
            if(objectName.startsWith(SymbolConstant.SINGLE_SLASH)){
                objectName = objectName.substring(1);
            }
            PutObjectArgs objectArgs = PutObjectArgs.builder().object(objectName)
                    .bucket(newBucket)
                    .contentType(contentType)
                    .stream(stream,stream.available(),-1).build();
            minioClient.putObject(objectArgs);
            stream.close();
            fileUrl = minioUrl+newBucket+"/"+objectName;
        }catch (Exception e){
            log.error(e.getMessage(), e);
        }
        return fileUrl;
    }

//    /**
//     * 文件上传
//     * @param file
//     * @param bizPath
//     * @return
//     */
//    public static String upload(MultipartFile file, String bizPath) throws Exception {
//        return upload(file,bizPath,null);
//    }

    /**
     * 获取文件流
     * @param bucketName
     * @param objectName
     * @return
     */
    public static InputStream getMinioFile(String bucketName,String objectName){
        InputStream inputStream = null;
        try {
            initMinio(minioUrl, minioName, minioPass);
            GetObjectArgs objectArgs = GetObjectArgs.builder().object(objectName)
                    .bucket(bucketName).build();
            inputStream = minioClient.getObject(objectArgs);
        } catch (Exception e) {
            log.info("文件获取失败" + e.getMessage());
        }
        return inputStream;
    }

    /**
     * 删除文件
     * @param bucketName
     * @param objectName
     * @throws Exception
     */
    public static void removeObject(String bucketName, String objectName) {
        try {
            initMinio(minioUrl, minioName,minioPass);
            RemoveObjectArgs objectArgs = RemoveObjectArgs.builder().object(objectName)
                    .bucket(bucketName).build();
            minioClient.removeObject(objectArgs);
        }catch (Exception e){
            log.info("文件删除失败" + e.getMessage());
        }
    }

    /**
     * 获取文件外链
     * @param bucketName
     * @param objectName
     * @param expires
     * @return
     */
    public static String getObjectUrl(String bucketName, String objectName, Integer expires) {
        initMinio(minioUrl, minioName,minioPass);
        try{
            //update-begin---author:liusq  Date:20220121  for：获取文件外链报错提示method不能为空，导致文件下载和预览失败----
            GetPresignedObjectUrlArgs objectArgs = GetPresignedObjectUrlArgs.builder().object(objectName)
                    .bucket(bucketName)
                    .expiry(expires).method(Method.GET).build();
            //update-begin---author:liusq  Date:20220121  for：获取文件外链报错提示method不能为空，导致文件下载和预览失败----
            String url = minioClient.getPresignedObjectUrl(objectArgs);
            return URLDecoder.decode(url,"UTF-8");
        }catch (Exception e){
            log.info("文件路径获取失败" + e.getMessage());
        }
        return null;
    }

    /**
     * 初始化客户端
     * @param minioUrl
     * @param minioName
     * @param minioPass
     * @return
     */
    private static MinioClient initMinio(String minioUrl, String minioName,String minioPass) {
        if (minioClient == null) {
            try {

//                //取消ssl认证
//                final TrustManager[] trustAllCerts = new TrustManager[]{
//                        new X509TrustManager() {
//                            @Override
//                            public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {
//                            }
//                            @Override
//                            public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {
//                            }
//                            @Override
//                            public X509Certificate[] getAcceptedIssuers() {
//                                return new X509Certificate[]{};
//                            }
//                        }
//                };
//
//                X509TrustManager x509TrustManager = (X509TrustManager) trustAllCerts[0];
//                final SSLContext sslContext = SSLContext.getInstance("SSL");
//                sslContext.init(null, trustAllCerts, new SecureRandom());
//                final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
//                OkHttpClient.Builder builder = new OkHttpClient.Builder();
//                builder.sslSocketFactory(sslSocketFactory,x509TrustManager);
//
//                builder.hostnameVerifier((s, sslSession) -> true);
//                OkHttpClient okHttpClient = builder.build();
//
//                minioClient= MinioClient.builder().endpoint(minioUrl).httpClient(okHttpClient).region("eu-west-1").credentials(minioName
//                        , minioPass).build();



                minioClient = MinioClient.builder()
                        .endpoint(minioUrl)
                        .credentials(minioName, minioPass)
                        .build();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return minioClient;
    }

    /**
     * 上传文件到minio
     * @param stream
     * @param relativePath
     * @return
     */
    public static String upload(InputStream stream,String relativePath) throws Exception {
        initMinio(minioUrl, minioName,minioPass);
        if(minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
            log.info("Bucket already exists.");
        } else {
            // 创建一个名为ota的存储桶
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            log.info("create a new bucket.");
        }
        PutObjectArgs objectArgs = PutObjectArgs.builder().object(relativePath)
                .bucket(bucketName)
                .contentType("application/octet-stream")
                .stream(stream,stream.available(),-1).build();
        minioClient.putObject(objectArgs);
        stream.close();
        return minioUrl+bucketName+"/"+relativePath;
    }



    /**
     * 上传文件
     * @param file 文件
     *  @param customBucket 自定义bucket
     * @return
     */
    public static String upload(MultipartFile file,  String customBucket) throws Exception {
        initMinio(minioUrl, minioName,minioPass);
        String fileUrl = "";
        // 获取文件名
        String orgName = file.getOriginalFilename();
        if ("".equals(orgName)) {
            orgName = file.getName();
        }
        orgName = CommonUtils.getFileName(orgName);
        String bizPath= determineFileType(orgName);
        String contentType = guessContentTypeFromName(orgName);
        //update-begin-author:wangshuai date:20201012 for: 过滤上传文件夹名特殊字符，防止攻击
        bizPath = StrAttackFilter.filter(bizPath);   //bizPath   可以理解到底是file 还是image    等等
        //update-end-author:wangshuai date:20201012 for: 过滤上传文件夹名特殊字符，防止攻击

        //update-begin-author:liusq date:20210809 for: 过滤上传文件类型
        SsrfFileTypeFilter.checkUploadFileType(file);
        //update-end-author:liusq date:20210809 for: 过滤上传文件类型

        String newBucket = bucketName;
        if(oConvertUtils.isNotEmpty(customBucket)){
            newBucket = customBucket;
        }
        try {
            // 检查存储桶是否已经存在
//            if(minioClient.bucketExists(BucketExistsArgs.builder().bucket(newBucket).build())) {
//                log.info("Bucket already exists.");
//            } else {
//                // 创建一个名为ota的存储桶
//                minioClient.makeBucket(MakeBucketArgs.builder().bucket(newBucket).build());
//                log.info("create a new bucket.");
//            }
            InputStream stream = file.getInputStream();

            String fileName = System.currentTimeMillis() + "-" + orgName;
            String objectName = bizPath + "/" + DateTimeUtils.getFormatDate(new Date(), DateTimeUtils.PARTDATEFORMAT) + "/" + fileName;
            System.out.println("objectName = " + objectName);

            // 使用putObject上传一个本地文件到存储桶中。
            if(objectName.startsWith(SymbolConstant.SINGLE_SLASH)){
                objectName = objectName.substring(1);
            }
            PutObjectArgs objectArgs = PutObjectArgs.builder().object(objectName)
                    .bucket(newBucket)
                    .contentType(contentType)
                    .stream(stream,stream.available(),-1).build();
            minioClient.putObject(objectArgs);
            stream.close();
            fileUrl = minioUrl+newBucket+"/"+objectName;
        }catch (Exception e){
            log.error(e.getMessage(), e);
        }
        return fileUrl;
    }
    /**
     * 上传文件
     *
     * @param file        文件
     * @param customBucket 自定义bucket
     * @return 文件访问URL
     */
    public static String upload(File file, String customBucket) throws Exception {
        initMinio(minioUrl, minioName, minioPass);
        String fileUrl = "";
        String orgName = file.getName();
        if ("".equals(orgName)) {
            orgName = file.getName();
        }
        orgName = CommonUtils.getFileName(orgName);
        String bizPath = determineFileType(orgName);
        String contentType = guessContentTypeFromName(orgName);

        // 防止攻击过滤
        bizPath = StrAttackFilter.filter(bizPath);
        SsrfFileTypeFilter.checkUploadFileType(file);

        String newBucket = bucketName;
        if (oConvertUtils.isNotEmpty(customBucket)) {
            newBucket = customBucket;
        }

        try {
            // 获取原始文件大小（MB）
            double fileSizeInMB = (double) file.length() / (1024 * 1024);
            log.info("Original file size: {} MB", fileSizeInMB);

            // 根据大小设定压缩质量
            float quality = 1.0f;
            if (fileSizeInMB < 1.0) {
                quality = 0.85f; // 几乎无损
            } else if (fileSizeInMB < 3.0) {
                quality = 0.65f; // 中等压缩
            } else {
                quality = 0.45f;  // 强压缩
            }

            // 使用Thumbnailator进行压缩（只改画质，不改尺寸）
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            Thumbnails.of(file)
                    .scale(1f) // 保持原图尺寸不变
                    .outputFormat("jpg") // 可选：如果希望统一输出格式为 jpg
                    .outputQuality(quality)
                    .toOutputStream(os);

            byte[] compressedBytes = os.toByteArray();
            ByteArrayInputStream inputStream = new ByteArrayInputStream(compressedBytes);

            // 构造对象名
            String fileName = System.currentTimeMillis() + "-" + orgName;
            String objectName = bizPath + "/" + DateTimeUtils.getFormatDate(new Date(), DateTimeUtils.PARTDATEFORMAT) + "/" + fileName;

            if (objectName.startsWith(SymbolConstant.SINGLE_SLASH)) {
                objectName = objectName.substring(1);
            }

            // 上传到 MinIO
            PutObjectArgs objectArgs = PutObjectArgs.builder()
                    .object(objectName)
                    .bucket(newBucket)
                    .contentType(contentType)
                    .stream(inputStream, compressedBytes.length, -1)
                    .build();

            minioClient.putObject(objectArgs);
            inputStream.close();

//            fileUrl = minioUrl + newBucket + "/" + objectName;
            fileUrl = newBucket + "/" + objectName;

        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        return fileUrl;
    }
    /**
     * 上传文件
     * @param file 文件
     *  @param customBucket 自定义bucket
     * @return
     */
    public static String upload3(File file, String customBucket) throws Exception {
        initMinio(minioUrl, minioName,minioPass);
        String fileUrl = "";
        // 获取文件名
        String orgName = file.getName();
        if ("".equals(orgName)) {
            orgName = file.getName();
        }
        orgName = CommonUtils.getFileName(orgName);
        String bizPath= determineFileType(orgName);
        String contentType = guessContentTypeFromName(orgName);
        //update-begin-author:wangshuai date:20201012 for: 过滤上传文件夹名特殊字符，防止攻击
        bizPath = StrAttackFilter.filter(bizPath);   //bizPath   可以理解到底是file 还是image    等等
        //update-end-author:wangshuai date:20201012 for: 过滤上传文件夹名特殊字符，防止攻击

        //update-begin-author:liusq date:20210809 for: 过滤上传文件类型
        SsrfFileTypeFilter.checkUploadFileType(file);
        //update-end-author:liusq date:20210809 for: 过滤上传文件类型

        String newBucket = bucketName;
        if(oConvertUtils.isNotEmpty(customBucket)){
            newBucket = customBucket;
        }
        try {
//
            InputStream stream= new FileInputStream(file);
//
//
            String fileName = System.currentTimeMillis() + "-" + orgName;
            String objectName = bizPath + "/" + DateTimeUtils.getFormatDate(new Date(), DateTimeUtils.PARTDATEFORMAT) + "/" + fileName;
            System.out.println("objectName = " + objectName);

            // 使用putObject上传一个本地文件到存储桶中。
            if(objectName.startsWith(SymbolConstant.SINGLE_SLASH)){
                objectName = objectName.substring(1);
            }
            PutObjectArgs objectArgs = PutObjectArgs.builder().object(objectName)
                    .bucket(newBucket)
                    .contentType(contentType)
                    .stream(stream,stream.available(),-1).build();
            minioClient.putObject(objectArgs);
            stream.close();
            fileUrl = minioUrl+newBucket+"/"+objectName;
            // 使用Thumbnails进行压缩
//            ByteArrayOutputStream os = new ByteArrayOutputStream();
//            Thumbnails.of(file)
//                    .scale(1f) // 保持原图比例
////                    .size(1280, 1280) // 设置最大宽度和高度，保持原图比例
//                    .outputQuality(1f) // 输出质量设置为70%
//                    .toOutputStream(os);
//
//            byte[] bytes = os.toByteArray();
//            ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);

//            String fileName = System.currentTimeMillis() + "-" + orgName;
//            String objectName = bizPath + "/" + DateTimeUtils.getFormatDate(new Date(), DateTimeUtils.PARTDATEFORMAT) + "/" + fileName;
//            System.out.println("objectName = " + objectName);
//
//            if(objectName.startsWith(SymbolConstant.SINGLE_SLASH)){
//                objectName = objectName.substring(1);
//            }
//            PutObjectArgs objectArgs = PutObjectArgs.builder().object(objectName)
//                    .bucket(newBucket)
//                    .contentType(contentType)
//                    .stream(inputStream,bytes.length,-1).build();
//            minioClient.putObject(objectArgs);
//            inputStream.close();

//            fileUrl = minioUrl+newBucket+"/"+objectName;
        }catch (Exception e){
            log.error(e.getMessage(), e);
        }
        return fileUrl;
    }


    /**
     * 文件上传
     * @param file
     * @param bizPath
     * @return
     */
    public static String upload1(MultipartFile file, String bizPath) throws Exception {
        return upload(file,bizPath,null);
    }


    /**
     * 根据文件名或路径判断文件类型是图像还是普通文件。
     *
     * @param filePathOrName 文件的完整路径或仅文件名
     * @return "image" 如果是图像文件，否则返回 "file"
     */
    private static String determineFileType(String filePathOrName) {
        int lastDotIndex = filePathOrName.lastIndexOf('.');
        if (lastDotIndex > 0 && lastDotIndex < filePathOrName.length() - 1) {
            String extension = filePathOrName.substring(lastDotIndex + 1).toLowerCase();
            switch (extension) {
                case "jpg":
                case "jpeg":
                case "png":
                case "gif":
                case "bmp":
                    return "image"; // 图像类型
                default:
                    return "file"; // 非图像类型
            }
        }
        return "file"; // 如果没有扩展名或扩展名不匹配，认为是非图像类型
    }

    // 辅助函数用于猜测contentType
    private static String guessContentTypeFromName(String name) {
        int lastDotIndex = name.lastIndexOf('.');
        if (lastDotIndex > 0 && lastDotIndex < name.length() - 1) {
            String extension = name.substring(lastDotIndex + 1).toLowerCase();
            switch (extension) {
                case "pdf":
                    return "application/pdf";
                case "jpg":
                case "jpeg":
                    return "image/jpeg";
                case "png":
                    return "image/png";
                case "gif":
                    return "image/gif";
                case "bmp":
                    return "image/bmp";
                case "doc":
                case "docx":
                    return "application/msword";
                case "xls":
                case "xlsx":
                    return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
                // 其他文件类型可以继续添加...
                default:
                    return "application/octet-stream"; // 默认值，用于未知文件类型
            }
        }
        return "application/octet-stream"; // 如果没有扩展名，也使用默认值
    }

}
